// Tree.cpp: implementation for the tree class.
// Copyright: (c) Project 5 Team (715), 2009
//////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "TreeModel.h"

namespace LifeSketchTree
{
double lineAngle(CVec2di* p1, CVec2di* p2)
{
	double x = (double)(p1->v[0] - p2->v[0]);
	double y = (double)(p1->v[1] - p2->v[1]);
	//printf("x: %f, y: %f",x,y);
	
	
	return atan2(y,x);
}

double lineAngle3D(CVec3df* p1, CVec3df* p2)
{
	//arccos(A.B / |A||B|)
	return acos(p1->dot(*p2) / (p1->length() * p2->length()));
}

CNode2D::CNode2D(CSketch* l, bool f) 
{
	//CNode2D(NULL, -1, line, forwards);
	parent = NULL;
	//parentIntersection = -1;
	StartPoint = NULL;
	axisPoint = new CVec2di(l->getRawControlPoints()->at(0)->v[X],l->getRawControlPoints()->at(0)->v[Y]-10);
	line = new CSketch(l);
	forwards = f;
	twig = false;
}

CNode2D::CNode2D(CNode2D* p, int pi, CSketch* l, bool f, bool isTwig) {
	//printf("new node2d line cntrl pt count = %d\n",l->ControlPoints()->size());
	line = new CSketch(l);
	parent = p;
	//parentIntersection = pi;
	StartPoint = p->getLine()->getRawControlPoints()->at(pi/*+1*/);
	if(pi<1)
		axisPoint = p->getLine()->getRawControlPoints()->at(pi+1/*+1*/);
	else 
		axisPoint = p->getLine()->getRawControlPoints()->at(pi-1/*+1*/);
	
	//printf("\nstartPoint: %i, %i", StartPoint->v[X], StartPoint->v[Y]);
	//printf("\naxisPoints: %i, %i", axisPoint->v[X], axisPoint->v[Y]);
	//line = l;
	forwards = f;
	twig = isTwig;
	parent->addChild(this);
	//this->left = left;
	//Calculate the angle that the branch makes with the connecting segment
	CVec2di* lastPoint;
	if(f)
		lastPoint = l->getRawControlPoints()->back();
	else 
		lastPoint = l->getRawControlPoints()->front();
	
	CVec2di* p1 = p->line->getRawControlPoints()->at(pi);
	CVec2di* p2;
	if(pi<1)
		p2 = new CVec2di(p1->v[X], p1->v[Y]-20);
	else 
		p2 = p->line->getRawControlPoints()->at(pi-1);
	
	double theta = lineAngle(p1,p2);
	double phi = lineAngle(p1, lastPoint);
	double angle1 = phi-theta + Pi;
	
	if(angle1 < 0)
		left = false; //?
	else
		left = true;
}

CNode2D::CNode2D(CNode2D* p, CSketch* l, CVec2di* StartPoint, CVec2di* axisPoint, bool isTwig, bool isLeft)
{
	this->left = isLeft;
	this->twig = isTwig;
	this->StartPoint = StartPoint;
	this->axisPoint = axisPoint;
	this->parent = p;
	this->line = l;
	//parent->addChild(this);
}

CNode2D::~CNode2D() {
	// hopefully the sketch is removed elsewhere
}

int CNode2D::depth() {
	return parent==NULL ? 0 : parent->depth()+1;
}

void CNode2D::addChild(CNode2D* child) {
	children.push_back(child);
}
bool CNode2D::isLeft()
{
	return left;
}


bool CNode2D::isTwig()
{
	return twig;
}
bool CNode2D::isForwards() {
	return forwards;
}

CNode2D* CNode2D::getParent() {
	return parent;
}
CSketch* CNode2D::getLine() {
	return line;
}

/*int CNode2D::getParentIntersection() {
 return parentIntersection;
 }*/

CVec2di* CNode2D::getStartPoint()
{
	return this->StartPoint;
}

CVec2di* CNode2D::getAxisPoint()
{
	return this->axisPoint;
}

vector<CNode2D*>* CNode2D::getChildren() {
	return &children;
}

//////////////////////////////////////////////////////////////////////

CNode3D::CNode3D(vector<CVec3df*>* l) {
	parent = NULL;
	//parentIntersection = -1;
	//axisPoint = 
	line = l;
	twig = false;
	left = false;
}

CNode3D::CNode3D(CNode3D* p, vector<CVec3df*>* l, bool lft, bool t) {
	//printf("new node2d line cntrl pt count = %d\n",l->ControlPoints()->size());
	parent = p;
	//parentIntersection = pi;
	line = l;
	twig = t;
	//parent->addChild(this);
	left = lft;
}

CNode3D::~CNode3D() 
{
	delete line;
}


int CNode3D::depth() {
	return parent==NULL ? 0 : parent->depth()+1;
}

void CNode3D::addChild(CNode3D* child) {
	children.push_back(child);
	child->setParent(this);
}

void CNode3D::setParent(CNode3D* p) {
	parent = p;
}
CNode3D* CNode3D::getParent() {
	return parent;
}
void CNode3D::setLine(vector<CVec3df*>* line) {
	line = line;
}
vector<CVec3df*>* CNode3D::getLine() {
	return line;
}



/*void CNode3D::setParentIntersection(int i) {
 parentIntersection = i;
 }
 */
int CNode3D::getParentIntersection() {
	for(int i = 0; i < parent->getLine()->size(); i++) {
		if (parent->getLine()->at(i) == line->at(0)) return i;
	}
	return 0;
}

CNode3D* CNode3D::copyNode()
{
	
	
	vector<CVec3df*>* vec = new vector<CVec3df*>();
	for(int i = 0; i < this->getLine()->size(); i++)
		vec->push_back(new CVec3df(*(this->getLine()->at(i))));
	
	//vector<CVec3df*>* vec = new vector<CVec3df*>();
	//for(int i = 0; i< this->getChildren()->size(); i++)
	CNode3D* node = new CNode3D(this->parent, vec, this->isLeft(), this->isTwig());
	node->setAxisPoint(new CVec3df(*(this->getAxisPoint())));
	node->setCopy(true);
	for(int i = 0; i< this->getChildren()->size(); i++)
		node->addChild(this->getChildren()->at(i)->copyNode());
	
	return node;
}


vector<CNode3D*>* CNode3D::getChildren() {
	return &children;
}

void CNode3D::setAngle(double angle)
{
	//printf("ROTATION CALLED");
	//Rotate all of the nodes in this branch and all of its children by that angle around the parent axis
	if(this->getParent() == NULL)
	{
		this->angle = 0.0;
		return;
	}
	
	this->angle = angle;
	
	CNode3D* parent = this->getParent();
	/*CVec3df* axis1 = parent->getLine()->at(this->getParentIntersection() + 1);
	 CVec3df* axis2;
	 if (this->getParentIntersection() < 1)
	 {
	 axis2 = parent->getLine()->at(this->getParentIntersection() + 2);
	 }
	 else
	 {
	 axis2 = parent->getLine()->at(this->getParentIntersection() - 0);
	 }*/
	CVec3df* axis1 = this->getLine()->at(0);
	CVec3df* axis2 = this->getAxisPoint();
	
	CVec3df axis = *axis1 - *axis2; 
	//printf("\n AxisLength: %f ", axis.length());
	this->rotateAroundAxis(*axis1, *axis2, angle);
}

void CNode3D::rotateAroundAxis(CVec3df axis1,CVec3df axis2, double r)
{
	vector<CVec3df*>* line3D = getLine();
	vector<CVec3df*>::iterator i;
	for (i = line3D->begin() ; i != line3D->end() ; i++) {
		(*i)->rotateAroundAxis(&axis1, &axis2, r);
	}
	vector<CNode3D*>::iterator j;
	for (j = this->getChildren()->begin(); j != this->getChildren()->end(); j++) {
		(*j)->rotateAroundAxis(axis1,axis2, r);
	}
}

void CNode3D::setLeft(bool isLeft)
{
	this->left = isLeft;
}

bool CNode3D::isTwig() {
	return twig;
}

void CNode3D::setTwig(bool t)
{
	twig = t;
}
bool CNode3D::isLeft()
{
	return this->left;
}
bool CNode3D::isCopy()
{
	return this->copy;
}
void CNode3D::setCopy(bool c)
{
	this->copy = c;
}

double CNode3D::angleOfBranch()
{
	return this->angle;
}

CVec3df* CNode3D::getAxisPoint()
{
	return this->axisPoint;
}
void CNode3D::setAxisPoint(CVec3df* point)
{
	this->axisPoint = point;
}
}